/* c++11 数组，实际为一个struct，内部有个C语言风格数组，
 * 比C风格数组优势，1.实际是一个struct，是一个单个整体 2. 不会退化成指针
 * */
#ifndef SPW_ARRAY_H_
#define SPW_ARRAY_H_

#include <exception/spw_stdexcept.h>
#include <algorithm/spw_algobase.h>
#include <spw_config.h>
namespace spwstd {
namespace spwarray {

/*  ArrayTraits 
 * 萃取获得数组的类型
 * 为了解决C风格数组Nm=0问题 */
template<typename ValueType, spwconfig::size_t Nm>
struct ArrayTraits {
    using ArrType = ValueType[Nm]; 

    static constexpr ValueType&
    s_ref(const ArrType& t, spwconfig::size_t n) noexcept {
        // 使用constexpr函数特性, 当参数是字面值，constexpr起作用
        // 参数t = const ValueType[Nm], t具有const性
        // 当ValueType 无const性。返回类型无const性，而t[n]具有
        return const_cast<ValueType&>(t[n]);
    }

    static constexpr ValueType*
    s_ptr(const ArrType& t) noexcept {
        return const_cast<ValueType*>(t);
    }
};

// Nm为0时的特殊情况
template<typename ValueType>
struct ArrayTraits<ValueType, 0> {
    struct ArrType{ }; // 自定义的类型

    static constexpr ValueType& 
    s_ref(const ArrType&, spwconfig::size_t) noexcept {
        // 获取nullptr所指向的值，段错误，程序崩溃
        // 引用nullptr
        return *static_cast<ValueType*>(nullptr);
    }

    // 直接返回nullptr，Nm为0没有数组
    static constexpr ValueType* 
    s_ptr(const ArrType&) noexcept {
        return nullptr;
    }
};

template <typename ValueT, spwconfig::size_t Nm>
struct Array {
    using ValueType = ValueT;
    using Pointer = ValueType*;
    using ConstPointer = const ValueType*;
    using Refer = ValueType&;
    using ConstRefer = const ValueType&;
    using Iterator = ValueType*;
    using ConstIterator = const ValueType*;
    using SizeType = spwconfig::size_t;
    using DifferType = spwconfig::ptrdiff_t;

    using AtType = ArrayTraits<ValueType, Nm>;
    typename AtType::ArrType    elems_; // 当Nm=0时，elems_为空类，至Array为空类

// - 元素访问
constexpr Pointer Data() noexcept {
    return AtType::s_ptr(elems_);
}

constexpr ConstPointer Data() const noexcept {
    return AtType::s_ptr(elems_);
}

constexpr Refer operator[](SizeType n) noexcept {
    return AtType::s_ref(elems_, n);
}

constexpr ConstRefer operator[](SizeType n) const noexcept {
    return AtType::s_ref(elems_, n);
}

// at成员函数，比operator[]多了边界检测的功能，如果访问超出数组范围，则抛出异常spwstd::out_of_range类型异常
constexpr Refer At(SizeType n) {
    if(n >= Nm) {
        throw spwexcept::OutOfRange("spwstd::spwexcept::OutOfRange");
    }
    return AtType::s_ref(elems_, n);
}

constexpr ConstRefer At(SizeType n) const {
    if(n >= Nm) {
        throw spwexcept::OutOfRange("spwstd::spwexcept::OutOfRange");
    }
    return AtType::s_ref(elems_, n);
}

constexpr Refer Front() noexcept {
    return *Begin();
}

constexpr ConstRefer Front() const noexcept {
    return *Cbegin();
}

constexpr Refer Back() noexcept {
    return Nm ? *(End() - 1) : *End();
}

constexpr ConstRefer Back() const noexcept {
    return Nm ? AtType::s_ref(elems_, Nm-1) 
        : AtType::s_ref(elems_, 0);
}

// 迭代器
constexpr Iterator Begin() noexcept {
    return Iterator(Data());
}
constexpr ConstIterator Begin() const noexcept {
    return ConstIterator(Data());
}
constexpr Iterator End() noexcept {
    return Iterator(Data() + Nm);
}
constexpr ConstIterator End() const noexcept {
    return ConstIterator(Data() + Nm);
}

constexpr ConstIterator Cend() const noexcept {
    return ConstIterator(Data() + Nm);
}

constexpr ConstIterator Cbegin() const noexcept {
    return ConstIterator(Data());
}

// 容量相关
constexpr SizeType Size() const noexcept {
    return Nm;
}

constexpr bool Empty() const noexcept {
    return Size()==0;
}

// 元素操作
// 用v填充该array
void Fill(const ValueType& v) {
    spwstd::spwalg::fillN(Begin(), Size(), v);
}

// 交换两个数组内容
void Swap(Array& other) noexcept {
    spwstd::spwalg::swapRanges(Begin(), End(), other.Begin());
}

};

/* 非成员函数
 * */

} // namespace spwarray
} // namespace spwstd
#endif //SPW_ARRAY_H_
